package se.dolkow.skola.datasakerhet.server;

import java.io.File;
import java.io.IOException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.Date;
import java.util.Scanner;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

import se.dolkow.skola.datasakerhet.server.storage.BoundStorage;
import se.dolkow.skola.datasakerhet.server.storage.Storage;
import se.dolkow.skola.datasakerhet.server.storage.User;

public class Server {

	
	public static void main(String[] args) {
		int port = 34567;
		if (args.length > 0) {
			port = Integer.parseInt(args[0]);
		}
		
		
		try {
			Formatter formatter = new Formatter() {
				public String format(LogRecord record) {
					String time = new Date(record.getMillis()).toString();
					return time + " " + record.getLevel().getLocalizedName() + ": " + formatMessage(record) + "\n";
				}
				
			};
			Logger log = Logger.getLogger("se.dolkow.skola.datasakerhet.server.storage");
			log.setLevel(Level.FINE);
			for(Handler h : log.getHandlers()) {
				log.removeHandler(h);
			}
			
			FileHandler fh = new FileHandler("serverlog.txt", true);
			fh.setLevel(Level.INFO);
			fh.setFormatter(formatter);
			log.addHandler(fh);
			
			ConsoleHandler ch = new ConsoleHandler();
			ch.setLevel(Level.FINE);
			ch.setFormatter(formatter);
			log.addHandler(ch);
			
			Storage storage = new Storage(new File("serverdb.txt"));
			
			SSLServerSocket listensocket = (SSLServerSocket)SSLServerSocketFactory.getDefault().createServerSocket(port);
			listensocket.setNeedClientAuth(true);
			while(true) {
				log.fine("Listening on port " + port);
				SSLSocket socket = (SSLSocket)listensocket.accept();
				SSLSession session = socket.getSession();
				
				try {
					X509Certificate cert = (X509Certificate)session.getPeerCertificates()[0];
					Scanner sc = new Scanner(cert.getSubjectX500Principal().getName("RFC1779")).useDelimiter(",");
					String uname = sc.next().trim();
					if (!uname.startsWith("CN=") || uname.length() <= 3) {
						throw new SSLPeerUnverifiedException("Couldn't parse CN from user cert.");
					}
					uname = uname.substring(3);
					User u = storage.getUser(uname);
					log.info("Authenticated user " + uname);
					Session s = new Session(new BoundStorage(storage, u), socket);
					s.handle();
				} catch (SSLPeerUnverifiedException e) {
					log.warning("Failed authentication from " + socket.getInetAddress());
				}
				
				socket.close();
			}

		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}
	
}
